`include "defines.v"

// 通用寄存器模块 
//一共有32个通用寄存器x0~x31，其中寄存器x0是只读寄存器并且其值固定为0
//寄存器1和寄存器2是指一条指令里涉及到的两个寄存器(源寄存器1和源寄存器2)
//读寄存器操作来自译码模块，并且读出来的寄存器数据也会返回给译码模块。写寄存器操作来自执行模块

module regs(

    input wire clk,
    input wire rst,

    // from ex
    input wire we_i,                      // 写寄存器标志
    input wire[`RegAddrBus] waddr_i,      // 写寄存器地址 `define RegAddrBus 4:0
    input wire[`RegBus] wdata_i,          // 写寄存器数据 `define RegBus 31:0

    // from id
    input wire[`RegAddrBus] raddr1_i,     // 读寄存器1地址

    // from id
    input wire[`RegAddrBus] raddr2_i,     // 读寄存器2地址

    //
    output wire  rf_1,
    output wire rf_2,
    output wire rf_3,
    output wire rf_4,
    // to id
    output reg[`RegBus] rdata1_o,         // 读寄存器1数据
    
    // to id
    output reg[`RegBus] rdata2_o         // 读寄存器2数据

    );

    reg[`RegBus] regs[0:`RegNum - 1]; //`define RegNum 32 

    wire  rf_1_ = regs[5][3];
    wire rf_2_ = regs[5][2];
    wire rf_3_ = regs[5][1];
    wire rf_4_ = regs[5][0];

    assign rf_1 = rf_1_;
    assign rf_2 = rf_2_;
    assign rf_3 = rf_3_;
    assign rf_4 = rf_4_;
    // 写寄存器
    always @ (posedge clk) begin
        if (rst == `RstDisable) begin
            // 优先ex模块写操作
            if ((we_i == `WriteEnable) && (waddr_i != `RegNumLog2'h0)) begin //`define RegNumLog2 5
                regs[waddr_i] <= wdata_i;
                end
        end 
    end

    // 读寄存器1
    always @ (*) begin
        if (rst == `RstEnable) begin
            rdata1_o = `ZeroWord;
        end else if (raddr1_i == `RegNumLog2'h0) begin
            rdata1_o = `ZeroWord;
        // 如果读地址等于写地址，并且正在写操作，则直接返回写数据
        end else if (raddr1_i == waddr_i && we_i == `WriteEnable) begin
            rdata1_o = wdata_i;
        end else begin
            rdata1_o = regs[raddr1_i];
        end
    end

    // 读寄存器2
    always @ (*) begin
        if (rst == `RstEnable) begin
            rdata2_o = `ZeroWord;
        end else if (raddr2_i == `RegNumLog2'h0) begin
            rdata2_o = `ZeroWord;
        // 如果读地址等于写地址，并且正在写操作，则直接返回写数据
        end else if (raddr2_i == waddr_i && we_i == `WriteEnable) begin
            rdata2_o = wdata_i;
        end else begin
            rdata2_o = regs[raddr2_i];
        end
    end


endmodule
